/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SLE_UTILS_OBSERVER_LIST_H
#define SLE_UTILS_OBSERVER_LIST_H

#include <list>
#include <functional>
#include <memory>
#include <mutex>
#include "iremote_object.h"
#include "sle_common_config.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
template <typename T>
class SleObserverList final {
public:
    SleObserverList() = default;
    ~SleObserverList();

    bool Register(std::shared_ptr<T> &observer);
    bool Unregister(std::shared_ptr<T> &observer);
    void ForEach(const std::function<void(std::shared_ptr<T>)> &observer);

private:
    std::mutex lock_{};
    std::list<std::shared_ptr<T>> obServers_{};
    SLE_DISALLOW_COPY_AND_ASSIGN(SleObserverList);
};

template <typename T>
SleObserverList<T>::~SleObserverList()
{
    std::lock_guard<std::mutex> lock(lock_);
    obServers_.clear();
}

template <typename T>
bool SleObserverList<T>::Register(std::shared_ptr<T> &observer)
{
    std::lock_guard<std::mutex> lock(lock_);
    for (auto it = obServers_.begin(); it != obServers_.end(); ++it) {
        if (*it == observer) {
            return true;
        }
    }
    obServers_.push_back(observer);
    return true;
}

template <typename T>
bool SleObserverList<T>::Unregister(std::shared_ptr<T> &observer)
{
    std::lock_guard<std::mutex> lock(lock_);
    for (auto it = obServers_.begin(); it != obServers_.end(); ++it) {
        if (*it == observer) {
            obServers_.erase(it);
            return true;
        }
    }
    return false;
}

template <typename T>
void SleObserverList<T>::ForEach(const std::function<void(std::shared_ptr<T>)> &observer)
{
    std::lock_guard<std::mutex> lock(lock_);
    for (const auto &it : obServers_) {
        if (it != nullptr) {
            observer(it);
        }
    }
}

class SleDeathRecipient : public IRemoteObject::DeathRecipient {
public:
    using ResetServiceFunc = std::function<void(const wptr<IRemoteObject> &object)>;

    explicit SleDeathRecipient(ResetServiceFunc resetFunc) : resetServiceFunc_(std::move(resetFunc)) {}

    ~SleDeathRecipient() override = default;

    void OnRemoteDied(const wptr<IRemoteObject> &object) override
    {
        if (this->resetServiceFunc_) {
            this->resetServiceFunc_(object);
        }
    }

private:
    ResetServiceFunc resetServiceFunc_;
};
} // SleStandard
} // NearLink
} // OHOS

#endif // SLE_UTILS_OBSERVER_LIST_H